package com.josework.springhelloworld.entity.Menu;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

@Data
@NoArgsConstructor
public class Dish extends Exception{
    private String name;
    private boolean vegetarian;
    private int calories;
    private Type type;
    public Dish(String name, boolean vegetarian, int calories, Type type) {
        this.name = name;
        this.vegetarian = vegetarian;
        this.calories = calories;
        this.type = type;
    }

    public int dishCaloriesComparator (Dish dish){
        if (this.getCalories() == dish.getCalories()){
            return 0;
        } else {
          return this.getCalories() - dish.getCalories();
        }
    }

    public static <T> Collector<T,?,Long> counting(){
        return Collectors.reducing(0L, e->1L,Long::sum);
    }


    @Override
    public String toString() {
        return name;
    }

    public enum Type { MEAT, FISH, OTHER }

    public enum CaloricLevel { DIET,  NORMAL, FAT }

    public CaloricLevel getCaloricLevel(){
        if (this.getCalories()<=400) return CaloricLevel.DIET;
        else if (this.getCalories()<=700) return CaloricLevel.NORMAL;
        else return CaloricLevel.FAT;
    }

    public static void main(String[] args) {
        List<Dish> menu = Arrays.asList(
                new Dish("pork", false, 800, Dish.Type.MEAT),
                new Dish("beef", false, 700, Dish.Type.MEAT),
                new Dish("chicken", false, 400, Dish.Type.MEAT),
                new Dish("french fries", true, 530, Dish.Type.OTHER),
                new Dish("rice", true, 350, Dish.Type.OTHER),
                new Dish("season fruit", true, 120, Dish.Type.OTHER),
                new Dish("pizza", true, 550, Dish.Type.OTHER),
                new Dish("prawns", false, 300, Dish.Type.FISH),
                new Dish("salmon", false, 450, Dish.Type.FISH)
        );

        List<Dish> threeHighCalarics = menu.stream()
                .filter( d -> d.getCalories()>300)
                .limit(3)
                .collect(Collectors.toList());
        Stream<Dish> s = threeHighCalarics.stream();
        s.forEach(System.out::println);

        List<Dish> meatCollect = menu.stream()
                .filter(d -> d.getType() == Type.MEAT)
                .limit(2)
                .collect(Collectors.toList());

        List<String> words = Arrays.asList("Java 8","Lambdas","In","Action");
        List<Integer> wordLength = words.stream()
                .map(String::length)
                .collect(Collectors.toList());
        String[] arrayWord = {"Hello","World"};
        List<String[]> wordsCollect = Stream.of(arrayWord)
                .map(word -> word.split(""))
                .distinct()
                .collect(Collectors.toList());

        List<Stream<String>> collect = Arrays.stream(arrayWord)
                // 将每个字符串转换为其字符构成的数组
                .map(word -> word.split(""))
                //让每个数组变成一个单独的流
                .map(Arrays::stream)
                .distinct()
                .collect(Collectors.toList());

        //使用flatMap方法，
        List<String> collect1 = Arrays.stream(arrayWord)
                // 将每个字符串转换为其字符构成的数组
                .map(w -> w.split(""))
                //将各个生成流扁平为单个流
                .flatMap(Arrays::stream)
                .distinct()
                .collect(Collectors.toList());

        Integer[] integerArray = {1,2,3,4,5};
        List<Integer> collect2 = Arrays.stream(integerArray)
                .map(i -> i * i)
                .collect(Collectors.toList());

        Integer[] integerArray1 = {1,2,3,6,7,9};
        Integer[] integerArray2 = {3,4,7,8,6};
        List<Integer[]> collect3 = Arrays.stream(integerArray1)
                .flatMap(i -> Arrays.stream(integerArray2)
                        .filter( j -> Objects.equals(i, j))
                        .map(j -> new Integer[]{i, j}))
                .collect(Collectors.toList());

        boolean b = menu.stream()
                .anyMatch(Dish::isVegetarian);

        System.out.println("--------------------------------------");
        Optional<Dish> dish = menu.stream()
                .filter(Dish::isVegetarian)
                .findAny();
        Dish dish1 = dish.get();

        int[] numbers = {2,4,5,6,7,8,9,90,54,23};
        int sum = Arrays.stream(numbers)
                .reduce(0,Integer::sum);
        OptionalInt reduce = Arrays.stream(numbers).reduce(Integer::min);
        Optional<Integer> reduce1 = menu.stream()
                .map(e -> 1)
                .reduce(Integer::sum);
        Integer integer = reduce1.get();
        OptionalInt optionalInt = Arrays.stream(numbers)
                .parallel()
                .reduce(Integer::sum);

        Integer reduce2 = menu.stream()
                .map(Dish::getCalories)
                //这里暗含了一个装箱成本,每个Integer都必须拆箱成一个原始类型，再进行求和。
                //虽然流中元素都是Integer类型，但是Stream接口没有定义sum方法。
                .reduce(0, Integer::sum);

        int calories = menu.stream()
                .mapToInt(Dish::getCalories)
                .sum();

        //将Stream转换为数值流
        IntStream intStream = menu.stream()
                .mapToInt(Dish::getCalories);
        //将数值流转换为Stream
        Stream<Integer> boxed = intStream.boxed();

        OptionalInt maxCalories = menu.stream()
                .mapToInt(Dish::getCalories)
                .max();
        int max = maxCalories.orElse(1);
        IntStream range = IntStream.range(1, 100);
        IntStream rangeNumbers = range.filter(n -> n % 2 == 0);
        System.out.println(rangeNumbers.count());


        Map<CaloricLevel, List<Dish>> levelListMap = menu
                .stream()
                .collect(Collectors.groupingBy(Dish::getCaloricLevel));
        List<Dish> dietList = levelListMap.get(CaloricLevel.DIET);


    }

}
